package cn.hyatt.common.utils;

import java.util.concurrent.atomic.AtomicLong;

public class SnowflakeIdGenerator {
    private final long twepoch = 1704038400000L; // 设置起始时间戳，这里以2024/1/1 00:00:00
    private final long workerIdBits = 5L;
    private final long maxWorkerId = ~(-1L << workerIdBits);
    private final long sequenceBits = 12L;

    private final long workerIdShift = sequenceBits;
    private final long timestampLeftShift = sequenceBits + workerIdBits;
    private final long sequenceMask = ~(-1L << sequenceBits);

    private long workerId;
    private AtomicLong sequence = new AtomicLong(0L);
    private long lastTimestamp = -1L;

    public SnowflakeIdGenerator(long workerId) {
        if (workerId > maxWorkerId || workerId < 0) {
            throw new IllegalArgumentException("Worker ID超出范围");
        }
        this.workerId = workerId;
    }

    public synchronized long generateId() {
        long timestamp = System.currentTimeMillis();

        if (timestamp < lastTimestamp) {
            throw new RuntimeException("时钟回拨异常");
        }

        if (timestamp == lastTimestamp) {
            long sequenceId = sequence.incrementAndGet() & sequenceMask;

            // 如果序列号超过了最大值，则等待下一毫秒
            if (sequenceId == 0) {
                timestamp = tilNextMillis(lastTimestamp);
            }
        } else {
            sequence.set(0L);
        }

        lastTimestamp = timestamp;

        // 根据时间戳、工作机器ID和序列号生成ID

        return ((timestamp - twepoch) << timestampLeftShift)
                | (workerId << workerIdShift)
                | sequence.get();
    }

    private long tilNextMillis(long lastTimestamp) {
        long timestamp = System.currentTimeMillis();
        while (timestamp <= lastTimestamp) {
            timestamp = System.currentTimeMillis();
        }
        return timestamp;
    }

    public static void main(String[] args) {
        SnowflakeIdGenerator idGenerator = new SnowflakeIdGenerator(6);
        long id = idGenerator.generateId();
        System.out.println("生成的ID为：" + id);
    }

}
